home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 6 code / TCP / NewsWatcher / NW Source / Shared Code / Reusable Source / apputil.c next >
Encoding:
C/C++ Source or Header  |  1995-01-05  |  14.9 KB  |  522 lines  |  [TEXT/MMCC]

  1. /*----------------------------------------------------------------------------
  2.  
  3.     apputil.c
  4.  
  5.     This reusable module contains utility routines for finding and running helper
  6.     applications.
  7.     
  8.     Adapted from DTS sample code "SignatureToApp" and "LaunchWithDoc"
  9.  
  10. ----------------------------------------------------------------------------*/
  11.  
  12. #include <string.h>
  13. #include <stdio.h>
  14.  
  15. #include "def.h"
  16. #include "apputil.h"
  17. #include "memutil.h"
  18. #include "fileutil.h"
  19. #include "strutil.h"
  20. #include "resutil.h"
  21.  
  22.  
  23.  
  24. /*----------------------------------------------------------------------------
  25.     FindRunningAppBySignature 
  26.     
  27.     Find a running app given its signature.
  28.     
  29.     Entry:    sig = signature of app.
  30.             
  31.     Exit:    function result = error code.
  32.                 = procNotFound if not running.
  33.             *fSpec = file spec of app. 
  34.             *psn = process serial number of running app.
  35. ----------------------------------------------------------------------------*/
  36.  
  37. static OSErr FindRunningAppBySignature (OSType sig, FSSpec *fSpec,
  38.     ProcessSerialNumber *psn)
  39. {
  40.     OSErr err = noErr;
  41.     ProcessInfoRec info;
  42.     
  43.     psn->highLongOfPSN = 0;
  44.     psn->lowLongOfPSN  = kNoProcess;
  45.     while (true) {
  46.         err = GetNextProcess(psn);
  47.         if (err != noErr) return err;
  48.         info.processInfoLength = sizeof(info);
  49.         info.processName = nil;
  50.         info.processAppSpec = fSpec;
  51.         err = GetProcessInformation(psn, &info);
  52.         if (err != noErr) return err;
  53.         if (info.processSignature == sig) return noErr;
  54.     }
  55. }
  56.  
  57.  
  58.  
  59. /*----------------------------------------------------------------------------
  60.     VolHasDesktopDB 
  61.     
  62.     Check to see if a volume supports the new desktop database.
  63.     
  64.     Entry:    vRefNum = vol ref num of volumn
  65.             
  66.     Exit:    function result = error code.
  67.             *hasDesktop = true if volume has the new desktop database.
  68. ----------------------------------------------------------------------------*/
  69.  
  70. static OSErr VolHasDesktopDB (short vRefNum, Boolean *hasDesktop)
  71. {
  72.     HParamBlockRec pb;
  73.     GetVolParmsInfoBuffer info;
  74.     OSErr err = noErr;
  75.     
  76.     pb.ioParam.ioCompletion = nil;
  77.     pb.ioParam.ioNamePtr = nil;
  78.     pb.ioParam.ioVRefNum = vRefNum;
  79.     pb.ioParam.ioBuffer = (Ptr)&info;
  80.     pb.ioParam.ioReqCount = sizeof(info);
  81.     err = PBHGetVolParmsSync(&pb);
  82.     *hasDesktop = err == noErr && (info.vMAttrib & (1L << bHasDesktopMgr)) != 0;
  83.     return err;
  84. }
  85.  
  86.  
  87.  
  88. /*----------------------------------------------------------------------------
  89.     FindAppOnVolume 
  90.     
  91.     Find an application on a volume.
  92.     
  93.     Entry:    sig = application signature.
  94.             vRefNum = vol ref num
  95.             
  96.     Exit:    function result = error code
  97.                 = afpItemNotFound if app not found on vol.
  98.             *file = file spec for application on volume.
  99. ----------------------------------------------------------------------------*/
  100.  
  101. static OSErr FindAppOnVolume (OSType sig, short vRefNum, FSSpec *file)
  102. {
  103.     DTPBRec pb;
  104.     OSErr err = noErr;
  105.     short ioDTRefNum, i;
  106.     FInfo fInfo;
  107.     FSSpec candidate;
  108.     unsigned long lastModDateTime, maxLastModDateTime;
  109.  
  110.     memset(&pb, 0, sizeof(DTPBRec));
  111.     pb.ioCompletion = nil;
  112.     pb.ioVRefNum = vRefNum;
  113.     pb.ioNamePtr = nil;
  114.     err = PBDTGetPath(&pb);
  115.     if (err != noErr) return err;
  116.     ioDTRefNum = pb.ioDTRefNum;
  117.  
  118.     memset(&pb, 0, sizeof(DTPBRec));
  119.     pb.ioCompletion = nil;
  120.     pb.ioIndex = 0;
  121.     pb.ioFileCreator = sig;
  122.     pb.ioNamePtr = file->name;
  123.     pb.ioDTRefNum = ioDTRefNum;
  124.     err = PBDTGetAPPLSync(&pb);
  125.     
  126.     if (err == fnfErr || err == paramErr) return afpItemNotFound;
  127.     if (err != noErr) return err;
  128.  
  129.     file->vRefNum = vRefNum;
  130.     file->parID = pb.ioAPPLParID;
  131.     
  132.     err = FSpGetFInfo(file, &fInfo);
  133.     if (err == noErr) return noErr;
  134.     
  135.     i = 1;
  136.     maxLastModDateTime = 0;
  137.     while (true) {
  138.         memset(&pb, 0, sizeof(DTPBRec)); 
  139.         pb.ioCompletion = nil;
  140.         pb.ioIndex = i;
  141.         pb.ioFileCreator = sig;
  142.         pb.ioNamePtr = candidate.name;
  143.         pb.ioDTRefNum = ioDTRefNum;
  144.         err = PBDTGetAPPLSync(&pb);
  145.         if (err != noErr) break;
  146.         candidate.vRefNum = vRefNum;
  147.         candidate.parID = pb.ioAPPLParID;
  148.         err = GetLastModDateTime(file, &lastModDateTime);
  149.         if (err == noErr) {
  150.             if (lastModDateTime > maxLastModDateTime) {
  151.                 maxLastModDateTime = lastModDateTime;
  152.                 *file = candidate;
  153.             }
  154.         }
  155.         i++;
  156.     }
  157.     
  158.     return maxLastModDateTime > 0 ? noErr : afpItemNotFound;
  159. }
  160.  
  161.  
  162.  
  163. /*----------------------------------------------------------------------------
  164.     FindAppFromSig 
  165.     
  166.     Find an application given its signature.
  167.     
  168.     Entry:    sig = application signature
  169.     
  170.     Entry:    running = nil to skip check for running app and just do
  171.                 a desktop database search for the disk file.
  172.             
  173.     Exit:    function result = error code.
  174.                 = fnfErr if app not found
  175.             *fSpec = file spec of application.
  176.             *running = true if app is running.
  177.             *psn = process serial number of app if running.
  178. ----------------------------------------------------------------------------*/
  179.  
  180. OSErr FindAppFromSig (OSType sig, FSSpec *fSpec, Boolean *running,
  181.      ProcessSerialNumber *psn)
  182. {
  183.     OSErr err = noErr;
  184.     short sysVRefNum, vRefNum, index;
  185.     Boolean hasDesktopDB;
  186.  
  187.     if (running != nil) {
  188.         err = FindRunningAppBySignature(sig, fSpec, psn);
  189.         *running = true;
  190.         if (err == noErr) return noErr;
  191.         *running = false;
  192.         if (err != procNotFound) return err;
  193.     }
  194.     err = GetSysVolume(&sysVRefNum);
  195.     if (err != noErr) return err;
  196.     vRefNum = sysVRefNum;
  197.     index = 0;
  198.     while (true) {
  199.         if (index == 0 || vRefNum != sysVRefNum) {
  200.             err = VolHasDesktopDB(vRefNum, &hasDesktopDB);
  201.             if (err != noErr) return err;
  202.             if (hasDesktopDB) {
  203.                 err = FindAppOnVolume(sig, vRefNum, fSpec);
  204.                 if (err != afpItemNotFound) return err;
  205.             }
  206.         }
  207.         index++;
  208.         err = GetIndVolume(index, &vRefNum);
  209.         if (err == nsvErr) return fnfErr;
  210.         if (err != noErr) return err;
  211.     }
  212. }
  213.  
  214.  
  215.  
  216. /*----------------------------------------------------------------------------
  217.     FindAppNameFromSig 
  218.     
  219.     Find an application name given its signature.
  220.     
  221.     Entry:    sig = application signature
  222.             
  223.     Exit:    function result = error code.
  224.                 = fnfErr if app not found
  225.             name = application name.
  226. ----------------------------------------------------------------------------*/
  227.  
  228. OSErr FindAppNameFromSig (OSType sig, StringPtr name)
  229. {
  230.     FSSpec fSpec;
  231.     OSErr err = noErr;
  232.     
  233.     err = FindAppFromSig(sig, &fSpec, nil, nil);
  234.     if (err != noErr) return err;
  235.     CopyPascalString(name, fSpec.name);
  236.     return noErr;
  237. }
  238.  
  239.  
  240.  
  241. /*----------------------------------------------------------------------------
  242.     LaunchAppWithDoc 
  243.     
  244.     Launch an application with an initial open document event.
  245.     
  246.     Entry:    running = true if application is running, in which case
  247.                 it is sent the odoc event.
  248.             appSpec = file spec of application.
  249.             *psn = process serial number of app if it is running.
  250.             docSpec = file spec of document.
  251.             launchFileFlags = file flags.
  252.             launchControlFlags = control flags.
  253.             
  254.     Exit:    function result = error code.
  255. ----------------------------------------------------------------------------*/
  256.  
  257. OSErr LaunchAppWithDoc (Boolean running, FSSpec *appSpec, ProcessSerialNumber *psn,
  258.     FSSpec *docSpec, unsigned short launchFileFlags, unsigned short launchControlFlags)
  259. {
  260.     ProcessSerialNumber thePSN;
  261.     LaunchParamBlockRec launchThis;
  262.     AEDesc target = {0, nil};
  263.     AEDesc docDesc = {0, nil};
  264.     AEDesc launchDesc = {0, nil};
  265.     AEDescList theList = {0, nil};
  266.     AliasHandle withThis = nil;
  267.     AppleEvent theEvent = {0, nil};
  268.     AppleEvent theReply = {0, nil};
  269.     OSErr err = noErr;
  270.     Boolean autoParamValue = false;
  271.  
  272.     if (running) thePSN = *psn;
  273.     err = AECreateDesc(typeProcessSerialNumber, &thePSN, sizeof(thePSN), &target); 
  274.     if (err != noErr) goto exit;
  275.     err = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, &target,
  276.         kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
  277.     if (err != noErr) goto exit;
  278.     err = AECreateList(nil, 0, false, &theList);
  279.     if (err != noErr) goto exit;
  280.     err = NewAlias(nil, docSpec, &withThis);
  281.     if (err != noErr) goto exit;
  282.     MyHLock(withThis);
  283.     err = AECreateDesc(typeAlias, (Ptr)*withThis, MyGetHandleSize(withThis), 
  284.         &docDesc);
  285.     if (err != noErr) goto exit;
  286.     MyHUnlock(withThis);
  287.     err = AEPutDesc(&theList, 0, &docDesc);
  288.     if (err != noErr) goto exit;
  289.     err = AEPutParamDesc(&theEvent, keyDirectObject, &theList);
  290.     if (err != noErr) goto exit;
  291.     if (running) {
  292.         err = AESend(&theEvent, &theReply, kAENoReply, kAENormalPriority, kNoTimeOut,
  293.             nil, nil);
  294.         if (err != noErr) goto exit;
  295.         if ((launchControlFlags & launchDontSwitch) == 0) {
  296.             err = SetFrontProcess(psn);
  297.             if (err != noErr) goto exit;
  298.         }
  299.     } else {
  300.         err = AECoerceDesc(&theEvent, typeAppParameters, &launchDesc);
  301.         if (err != noErr) goto exit;
  302.         MyHLock(theEvent.dataHandle);
  303.         launchThis.launchAppSpec = appSpec;
  304.         launchThis.launchAppParameters = (AppParametersPtr)*launchDesc.dataHandle;
  305.         launchThis.launchBlockID = extendedBlock;
  306.         launchThis.launchEPBLength = extendedBlockLen;
  307.         launchThis.launchFileFlags = launchFileFlags;
  308.         launchThis.launchControlFlags = launchControlFlags;
  309.         err = LaunchApplication(&launchThis);
  310.     }
  311.     
  312. exit:
  313.  
  314.     MyDisposeHandle(withThis);
  315.     if (target.dataHandle != nil) AEDisposeDesc(&target);
  316.     if (docDesc.dataHandle != nil) AEDisposeDesc(&docDesc);
  317.     if (launchDesc.dataHandle != nil) AEDisposeDesc(&launchDesc);
  318.     if (theList.dataHandle != nil) AEDisposeDesc(&theList);
  319.     if (theEvent.dataHandle != nil) AEDisposeDesc(&theEvent);
  320.     if (theReply.dataHandle != nil) AEDisposeDesc(&theReply);
  321.     return err;
  322. }
  323.  
  324.  
  325.  
  326. /*----------------------------------------------------------------------------
  327.     LaunchAppWithEventAndString 
  328.     
  329.     Launch an application with an initial event with a string parameter.
  330.     
  331.     Entry:    running = true if application is running, in which case
  332.                 it is sent the odoc event.
  333.             appSpec = file spec of application.
  334.             *psn = process serial number of app if it is running.
  335.             eventClass = event class.
  336.             eventID = event id.
  337.             keyword = parameter keyword (keyDirectObject if string is the
  338.                 direct object).
  339.             str = the string parameter for the event.
  340.             launchFileFlags = file flags.
  341.             launchControlFlags = control flags.
  342.             
  343.     Exit:    function result = error code.
  344. ----------------------------------------------------------------------------*/
  345.  
  346. OSErr LaunchAppWithEventAndString (Boolean running, FSSpec *appSpec, ProcessSerialNumber *psn,
  347.     OSType eventClass, OSType eventID, OSType keyword, char *str, 
  348.     unsigned short launchFileFlags, unsigned short launchControlFlags)
  349. {
  350.     ProcessSerialNumber thePSN;
  351.     LaunchParamBlockRec launchThis;
  352.     AEDesc target = {0, nil};
  353.     AEDesc stringDesc = {0, nil};
  354.     AEDesc launchDesc = {0, nil};
  355.     AppleEvent theEvent = {0, nil};
  356.     AppleEvent theReply = {0, nil};
  357.     OSErr err = noErr;
  358.     Boolean autoParamValue = false;
  359.  
  360.     if (running) thePSN = *psn;
  361.     err = AECreateDesc(typeProcessSerialNumber, &thePSN, sizeof(thePSN), &target); 
  362.     if (err != noErr) goto exit;
  363.     err = AECreateAppleEvent(eventClass, eventID, &target,
  364.         kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
  365.     if (err != noErr) goto exit;
  366.     err = AECreateDesc(typeChar, str, strlen(str), &stringDesc);
  367.     if (err != noErr) goto exit;
  368.     err = AEPutParamDesc(&theEvent, keyword, &stringDesc);
  369.     if (err != noErr) goto exit;
  370.     if (running) {
  371.         err = AESend(&theEvent, &theReply, kAENoReply, kAENormalPriority, kNoTimeOut,
  372.             nil, nil);
  373.         if (err != noErr) goto exit;
  374.         if ((launchControlFlags & launchDontSwitch) == 0) {
  375.             err = SetFrontProcess(psn);
  376.             if (err != noErr) goto exit;
  377.         }
  378.     } else {
  379.         err = AECoerceDesc(&theEvent, typeAppParameters, &launchDesc);
  380.         if (err != noErr) goto exit;
  381.         MyHLock(theEvent.dataHandle);
  382.         launchThis.launchAppSpec = appSpec;
  383.         launchThis.launchAppParameters = (AppParametersPtr)*launchDesc.dataHandle;
  384.         launchThis.launchBlockID = extendedBlock;
  385.         launchThis.launchEPBLength = extendedBlockLen;
  386.         launchThis.launchFileFlags = launchFileFlags;
  387.         launchThis.launchControlFlags = launchControlFlags;
  388.         err = LaunchApplication(&launchThis);
  389.     }
  390.     
  391. exit:
  392.  
  393.     if (target.dataHandle != nil) AEDisposeDesc(&target);
  394.     if (stringDesc.dataHandle != nil) AEDisposeDesc(&stringDesc);
  395.     if (launchDesc.dataHandle != nil) AEDisposeDesc(&launchDesc);
  396.     if (theEvent.dataHandle != nil) AEDisposeDesc(&theEvent);
  397.     if (theReply.dataHandle != nil) AEDisposeDesc(&theReply);
  398.     return err;
  399. }
  400.  
  401.  
  402.  
  403. /*----------------------------------------------------------------------------
  404.     AppCanOpenFileType
  405.  
  406.     Check to see if an application can open a given type of file.
  407.     
  408.     Entry:    pb = pointer to file info param block for a file of type
  409.                 'APPL' or 'adrp'.
  410.             fileType = file type.
  411.             
  412.     Exit:    function result = true if app can open files of the specified type.
  413. ----------------------------------------------------------------------------*/
  414.  
  415. Boolean AppCanOpenFileType (CInfoPBPtr pb, OSType fileType)
  416. {
  417.     FSSpec fSpec;
  418.     short refNum = 0;
  419.     short i;
  420.     Handle frefHandle;
  421.     Boolean targetIsFolder, wasAliased;
  422.     OSErr err = noErr;
  423.     FInfo fndrInfo;
  424.         
  425.     fSpec.vRefNum = pb->hFileInfo.ioVRefNum;
  426.     fSpec.parID = pb->hFileInfo.ioFlParID,
  427.     CopyPascalString(fSpec.name, pb->hFileInfo.ioNamePtr);
  428.     
  429.     if (pb->hFileInfo.ioFlFndrInfo.fdType == 'adrp') {
  430.         err = ResolveAliasFile(&fSpec, true, &targetIsFolder, &wasAliased);
  431.         if (err != noErr || targetIsFolder) return false;
  432.         err = FSpGetFInfo(&fSpec, &fndrInfo);
  433.         if (err != noErr) return false;
  434.         if (fndrInfo.fdType != 'APPL') return false;
  435.     }
  436.         
  437.     SetResLoad(false);
  438.     err = MyFSpOpenResFile(&fSpec, fsRdPerm, &refNum);
  439.     SetResLoad(true);
  440.     if (err != noErr) goto exit;
  441.     
  442.     for (i = 1; ; i++) {
  443.         err = MyGet1IndResource('FREF', i, &frefHandle);
  444.         if (err != noErr) goto exit;
  445.         if (**(OSType**)frefHandle == fileType) break;
  446.         if (**(OSType**)frefHandle == '****') break;
  447.     }
  448.     
  449.     MyCloseResFile(refNum);
  450.     return true;
  451.     
  452. exit:
  453.     
  454.     if (refNum != 0) MyCloseResFile(refNum);
  455.     return false;
  456. }
  457.  
  458.  
  459.  
  460. /*----------------------------------------------------------------------------
  461.     FileIsApplication
  462.  
  463.     Check to see if a file is an application or an alias to an application.
  464.     
  465.     Entry:    pb = pointer to file info param block for a file of type
  466.                 'APPL' or 'adrp'.
  467.             
  468.     Exit:    function result = true if application.
  469. ----------------------------------------------------------------------------*/
  470.  
  471. Boolean FileIsApplication (CInfoPBPtr pb)
  472. {
  473.     FSSpec fSpec;
  474.     Boolean targetIsFolder, wasAliased;
  475.     OSErr err = noErr;
  476.     FInfo fndrInfo;
  477.         
  478.     if (pb->hFileInfo.ioFlFndrInfo.fdType == 'APPL') return true;
  479.     if (pb->hFileInfo.ioFlFndrInfo.fdType != 'adrp') return false;
  480.     fSpec.vRefNum = pb->hFileInfo.ioVRefNum;
  481.     fSpec.parID = pb->hFileInfo.ioFlParID,
  482.     CopyPascalString(fSpec.name, pb->hFileInfo.ioNamePtr);
  483.     err = ResolveAliasFile(&fSpec, true, &targetIsFolder, &wasAliased);
  484.     if (err != noErr || targetIsFolder) return false;
  485.     err = FSpGetFInfo(&fSpec, &fndrInfo);
  486.     if (err != noErr) return false;
  487.     return fndrInfo.fdType == 'APPL';
  488. }
  489.  
  490.  
  491.  
  492. /*----------------------------------------------------------------------------
  493.     GetAppVersionNumber
  494.     
  495.     Get the version number of an application..
  496.     
  497.     Entry:    fSpec = pointer to application file spec.
  498.     
  499.     Exit:    function result = error code.
  500.             *versionNumber = version number.
  501. ----------------------------------------------------------------------------*/
  502.  
  503. OSErr GetAppVersionNumber (FSSpec *fSpec, unsigned long *versionNumber)
  504. {
  505.     OSErr err = noErr;
  506.     short refNum = 0;
  507.     
  508.     SetResLoad(false);
  509.     err = MyFSpOpenResFile(fSpec, fsRdPerm, &refNum);
  510.     SetResLoad(true);
  511.     if (err != noErr) goto exit;
  512.     err = GetVersionNumber(versionNumber);
  513.     if (err != noErr) goto exit;
  514.     MyCloseResFile(refNum);
  515.     return noErr;
  516.  
  517. exit:
  518.  
  519.     if (refNum != 0) MyCloseResFile(refNum);
  520.     return err;
  521. }
  522.